name: Trivy Scan
on:
  workflow_dispatch: {}
  schedule:
    # run every day at 3:07am UTC
    - cron: '7 3 * * *'

env:
  DOCKER_USR: ${{ secrets.DOCKER_USR }}

jobs:
  generate-matrix:
    runs-on: ubuntu-latest
    if: github.repository == 'crossplane/crossplane'
    outputs:
      versions: ${{ steps.get-releases.outputs.versions}}
      supported_releases: ${{ steps.get-releases.outputs.supported_releases }}
    steps:
      - name: Checkout
        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
        with:
          fetch-depth: 0

      - name: Get Last 3 Releases
        id: get-releases
        shell: bash
        ## find the 3 latest supported releases and their latest patch releases, storing them in the steps' outputs
        run: |
          # get the last 3 releases in "vX.Y" form
          supported_releases="$(git for-each-ref --sort='-committerdate' --format='%(refname:short)' --count=3 'refs/remotes/origin/release-*' | sed 's/.*release-/v/g')"
          if [ -z "$supported_releases" ]
          then
            echo "DEBUG: No supported releases found"
            echo "DEBUG: $(git for-each-ref 'refs/remotes')"
            exit 1
          fi

          echo "DEBUG: ${supported_releases}"

          # get the latest non-rc tag for each release
          tags=""
          while IFS= read -r version; do
            tag="$(git for-each-ref --sort=-taggerdate --count=1 'refs/tags/'${version}'.[\!-rc.*]' --format='%(tag)')"
            if [ -z "$tag" ]
            then
              echo "No tags found for version ${version}, ${tag}"
              echo "DEBUG: $(git for-each-ref 'refs/tags')"
              exit 1
            fi
            tags="${tags} ${version}=${tag}"
          done <<< "${supported_releases}"

          echo "DEBUG: ${tags}"

          # build a JSON formatted list of all the supported releases for crossplane/crossplane
          supported_releases=$(echo $supported_releases | jq -R .| jq -s -c '.[] | split(" ")')
          ## build a map of all the supported releases and their latest tags for later usage
          versions=$(echo $tags | jq -R .| jq -s -c '.[] | split(" ") | [.[] | select(length > 0) | [split("=")] | map({key: .[0], value: .[1]}) | .[] ] | from_entries' )

          # store everything as outputs
          echo "versions=${versions}" >> $GITHUB_OUTPUT
          echo "supported_releases=${supported_releases}" >> $GITHUB_OUTPUT

          echo "DEBUG: GITHUB_OUTPUT:"
          cat $GITHUB_OUTPUT

  check-matrix:
    # this job is just to check the matrix definition is valid and helps debugging it if not valid
    runs-on: ubuntu-latest
    needs:
      - generate-matrix
    steps:
      - name: Check Matrix Definition
        shell: bash
        run: |
          supported_releases='${{ needs.generate-matrix.outputs.supported_releases }}'
          echo $supported_releases
          echo $supported_releases | jq .

  scan:
    needs:
      - check-matrix
      - generate-matrix
    strategy:
      fail-fast: false
      matrix:
        release: ${{ fromJSON(needs.generate-matrix.outputs.supported_releases) }}
        image:
          - crossplane/crossplane

    runs-on: ubuntu-latest
    steps:
      - name: Get Release Tag
        run: |
          echo "${{ matrix.release }}"
          tag="$(echo '${{ needs.generate-matrix.outputs.versions }}' | jq --raw-output ".[\"${{ matrix.release }}\"]")"
          echo "tag=${tag}" >> $GITHUB_ENV
          echo "escaped_filename=$(echo ${{ matrix.image }}/$tag | sed 's/[\/.:]/_/g')" >> $GITHUB_ENV

      # we log to DockerHub to avoid rate limiting
      - name: Login To DockerHub
        uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3
        if: env.DOCKER_USR != ''
        with:
          username: ${{ secrets.DOCKER_USR }}
          password: ${{ secrets.DOCKER_PSW }}

      # we pull the image to be sure we're scanning the latest sha available
      - name: Pull Latest Image
        run: docker pull ${{ matrix.image }}:${{ env.tag }}

      - name: Run Trivy Vulnerability Scanner
        uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef # 0.17.0
        with:
          image-ref: ${{ matrix.image }}:${{ env.tag }}
          format: 'sarif'
          output: 'trivy-results.sarif'

      - name: Upload Artifact
        uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4
        with:
          name: trivy-${{ env.escaped_filename }}.sarif
          path: trivy-results.sarif
          retention-days: 3

      - name: Upload Trivy Scan Results To GitHub Security Tab
        uses: github/codeql-action/upload-sarif@e8893c57a1f3a2b659b6b55564fdfdbbd2982911 # v3
        with:
          sarif_file: 'trivy-results.sarif'
          category: ${{ matrix.image }}:${{ env.tag }}

